﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;
using System.Diagnostics;

namespace Engine.Sgml.Matching {
    internal sealed class AnyOrderModelMatcher {
        private ModelMatcher matcher;

        public AnyOrderModelMatcher(ModelMatcher matcher) {
            Guard.ArgumentNotNull(matcher, "matcher");
            this.matcher = matcher;
            }

        public void Match(ref Match match, ref SElement element, DContentModel contentModel) {
            do {
                ModelMatcher.MatchInclusions(match, ref element, contentModel);
                if (element == null)
                    break;
                IModelGroupsNode groupItem = match.Model.FirstItem;
                do {
                    if (groupItem.IsModelGroups()) {
                        Match inner = new Match(groupItem.FirstItem.Parent, match.Ancestor, match);
                        matcher.Match(inner, ref element, contentModel);
                        if (inner.HasMatches) {
                            if (match.Captures.Contains(groupItem) && !groupItem.CanRecur()) {
                                element = inner.StartElement;
                                MatchFinalizer.Finalize(match);
                                return;
                                }
                            match.Captures.Add(inner, true);
                            matcher.MatchRepetitive(match, inner.Model, ref element, contentModel);
                            break;
                            }
                        }
                    else if (ElementMatcher.Match(element, groupItem)) {
                        if (groupItem.CanRecur()) {
                            match.Captures.Add(groupItem, element);
                            element = element.NextNode;
                            while (element != null) {
                                if (ElementMatcher.Match(element, groupItem))
                                    match.Captures.Add(groupItem, element);
                                else if (contentModel.Inclusions.Contains(element.DName))
                                    match.Captures.Add(InclusionNode.Instance, element);
                                else
                                    break;
                                element = element.NextNode;
                                }
                            break;
                            }
                        else if (match.Captures.Contains(groupItem)) {
                            MatchFinalizer.Finalize(match);
                            return;
                            }
                        else {
                            match.Captures.Add(groupItem, element);
                            element = element.NextNode;
                            }
                        break;
                        }
                    groupItem = groupItem.NextItem();
                    } while (groupItem != null);
                if (groupItem == null)
                    break;
                } while (element != null);
            MatchFinalizer.Finalize(match);
            }
        }
    }